# Kestrel: An XMPP-based Many-Task Computing Scheduler
# Author: Lance Stout <lancestout@gmail.com>
#
# Copyright 2009-2010 Clemson University
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
The event engine allows for broadcasting messages between modules and
is a foundation for building up functionality by adding roles and modules.
"""

from threading import Thread, Lock
from Queue import Queue


class EventEngine(Thread):
    """
    A central, threaded event engine that can broadcast
    messages between application modules. It serves as a
    foundation for more advanced functionality provided
    through roles and modules.
    """

    def __init__(self):
        super(EventEngine, self).__init__()
        self.reqs = Queue()
        self.handlers = {}
        self.lock = Lock()

        # Events controlling the engine's operation:
        # ------------------------------------------
        self.START = 'events/start'
        self.STOP = 'events/stop'
        self.TERMINATE = 'events/terminate'

    def run(self):
        """
        Listen for events and trigger event handlers.
        """
        while True:
            req, args = self.reqs.get()
            if args is None:
                args = tuple()
            print req, args
            for handler in self.handlers.get(req, []):
                handler(*args)
            if req == self.TERMINATE:
                break

    def event(self, name, *args):
        """
        Raise an event with the given arguments.
        """
        self.reqs.put((name, args))

    def start(self):
        """
        Start the engine thread and begin listening for events.
        """
        self.reqs.put((self.START, None))
        super(EventEngine, self).start()

    def terminate(self):
        """
        Shutdown the engine immediately.
        """
        self.reqs.put((self.TERMINATE, None))

    def stop(self):
        """
        Signal all modules to stop. The engine will still accept events so
        that it can be restarted. To completely shutdown the engine, raise
        the terminate event after calling this method.
        """
        self.reqs.put((self.STOP, None))

    def add_handler(self, event, func):
        """
        Add a handler function for an event.
        """
        with self.lock:
            if self.handlers.get(event, None) is None:
                self.handlers[event] = []
            self.handlers[event].append(func)

    def del_handler(self, event, func):
        """
        Remove a handler function from an event.
        """
        with self.lock:
            if self.handlers.get(event, None) is not None:
                if func in self.handlers[event]:
                    self.handlers[event].remove(func)
